from typing import List, Tuple
import numpy as np
import math
import sys
from pathlib import Path
sys.path.append(str(Path(__file__).parent.parent))
from consts import CARD_TYPE, SCORE_BASE

CARD_MAX = 13
Total_N = 52
# 同花顺
# 4条
# 葫芦（3+2）
# 同花
# 顺子
# 3条
# 2对
# 对子
# 单牌

def straight_score(card_arr):
    '''
        顺子等级从10到0 -> TJQKA 到 A2345
        考虑同花时无 TJQKA, 最大9TJQK， 等级 9 _ 0
    '''
    arr_len = len(card_arr)
    for i in range(arr_len-5+1):
        if all(card_arr[arr_len - i - 5:arr_len - i]):
            return arr_len - i
    return -1

def royal_flush_judge(card_arr):
    # 皇家同花顺，TJQKA
    card_arr = np.concatenate([card_arr[:, 9:], card_arr[:, 0:1]], axis=-1)
    royal_flush_arr = card_arr.all(1)
    if royal_flush_arr.any():
        return 4-np.where(royal_flush_arr)[0].item()
    return -1

def flush_straight_judge(card_arr):
    # 一共有C(4,1)*9 = 36种
    # A~5, 最大9~K
    # 为了简化不考虑花色 9 种
    for i in range(4):
        # 花色评分
        _straight_score = straight_score(card_arr[i])
        if _straight_score >= 0:
            score = _straight_score
            return score
    return -1

def four_judge(card_arr):
    # 一共有 C(13, 1) * C(52-4, 1) = 624 [四条的牌 * 单牌]
    # 算大头，只算四条的排序
    card_arr = np.concatenate([card_arr[:, 1:], card_arr[:, 0:1]], axis=-1)
    four_card_arr = card_arr.all(0)
    if four_card_arr.any():
        return np.where(four_card_arr)[0].item()
    return -1

def three_score(card_arr):
    three_card = np.where(card_arr==3)[0]
    if len(three_card) != 0:
        _score = max(np.where(card_arr==3)[0])*13
        return _score
    return -1

def pair_score(card_arr):
    three_card = np.where(card_arr==2)[0]
    if len(three_card) != 0:
        _score = max(np.where(card_arr==2)[0])*13
        return _score
    return -1

def full_house_judge(card_arr):
    """
        一共有C(13, 1) * C(12, 1) * C(4,2) = 936
        不考虑对子花色则实际只有 936/C(4,2) = 156
    """
    card_arr = np.concatenate([card_arr[:, 1:], card_arr[:, 0:1]], axis=-1)
    card_arr = card_arr.sum(0)
    _three_score = three_score(card_arr)
    _pair_score = pair_score(card_arr)
    if _three_score != -1 and _pair_score != -1:
        _score = _three_score + _pair_score
        return _score if _score != 0 else -1
    return -1

def flush_judge(card_arr):
    # 一共有 C(4, 1) * C(13, 5) = 5148 种情况
    # 为简化，只考虑最大牌时则只有 C(4, 1)*8 = 32 最小为7，最大为A（最小为6时为同花顺） 
    card_arr = np.concatenate([card_arr[:, 1:], card_arr[:, 0:1]], axis=-1)
    card_n = card_arr.sum(1)
    if len(np.where(card_n>=5)[0])>0:
        idx = min(np.where(card_n>=5)[0])
        return max(np.where(card_arr[idx])[0])
    return -1

def straight_judge(card_arr):
    """
        不考虑牌色, 共有10种, 最小 A2345 最大 TJQKA
    """
    straight_card_arr = np.concatenate([card_arr, card_arr[:, 0:1]], axis=-1)
    straight_card_arr = straight_card_arr.sum(0)
    _score = straight_score(straight_card_arr)
    return _score

def three_judge(card_arr):
    """
        只判断3条，不考虑对子（会先考虑）
    """
    card_arr = np.concatenate([card_arr[:, 1:], card_arr[:, 0:1]], axis=-1)
    card_arr = card_arr.sum(0)
    _three_score = three_score(card_arr)
    return _three_score

def two_pair_judge(card_arr):
    """
        只考虑2对，不考虑单牌
        C(13, 1)*C(12, 1)
    """
    card_arr = np.concatenate([card_arr[:, 1:], card_arr[:, 0:1]], axis=-1)
    pair_arr = card_arr.sum(0)
    pair_idx = np.where(pair_arr == 2)[0].tolist()
    if len(pair_idx)>=2:
        max_pair_idx = sorted(pair_idx)[-2:]
        pair_score = max_pair_idx[0]+max_pair_idx[1]
        return pair_score
    return -1

def pair_judge(card_arr):
    """
        只考虑对子
        C(13, 1)
    """
    card_arr = np.concatenate([card_arr[:, 1:], card_arr[:, 0:1]], axis=-1)
    pair_arr = card_arr.sum(0)
    pair_idx = np.where(pair_arr == 2)[0].tolist()
    if len(pair_idx)>0:
        pair_score = sum(sorted(pair_idx)[-5:])
        return pair_score 
    return -1

def single_judge(card_arr):
    """
        C(13, 5) - 10 = 1277
    """
    card_arr = np.concatenate([card_arr[:, 1:], card_arr[:, 0:1]], axis=-1)
    single_arr = card_arr.sum(0)
    single_idx = np.where(single_arr > 0)[0].tolist()
    single_score = sum(sorted(single_idx)[-5:])
    return single_score

def card_judge(card_arr:np.ndarray) -> Tuple[CARD_TYPE, float]:
    """
        共有十种牌型，每种牌型单独打分
    """
    card_arr = card_arr.reshape((4, -1))
    # 皇家同花顺评分
    royal_flush_score = royal_flush_judge(card_arr)
    if royal_flush_score != -1:
        return CARD_TYPE.ROYAL_STRAIGHT, royal_flush_score
    # 同花顺评分
    flush_straight_score = flush_straight_judge(card_arr)
    if flush_straight_score != -1:
        return CARD_TYPE.FLUSH_STRAIGHT, flush_straight_score
    # 四条评分
    four_score = four_judge(card_arr)
    if four_score != -1:
        return CARD_TYPE.FOUR, four_score
    # 葫芦评分
    full_house_score = full_house_judge(card_arr)
    if full_house_score != -1:
        return CARD_TYPE.FULL_HOUSE, full_house_score
    # 同花
    flush_score = flush_judge(card_arr)
    if flush_score != -1:
        return CARD_TYPE.FLUSH, flush_score
    # 顺子
    straight_score = straight_judge(card_arr)
    if straight_score != -1:
        return CARD_TYPE.STRAIGHT, straight_score
    # 3条
    three_score = three_judge(card_arr)
    if three_score != -1:
        return CARD_TYPE.THREE, three_score
    # 2对
    two_pair_score = two_pair_judge(card_arr)
    if two_pair_score != -1:
        return CARD_TYPE.TWO_PAIR, two_pair_score
    # 对子
    pair_score = pair_judge(card_arr)
    if pair_score != -1:
        return CARD_TYPE.PAIR, pair_score
    # 单牌
    single_score = single_judge(card_arr)
    return CARD_TYPE.SINGLE, single_score

if __name__ == '__main__':
    # 皇家同花
    card_arr = np.array([
        [1]+[0]*12 + [1]+[0]*8+[1]*4  + [1]+[0]*12 + [1]+[0]*12
    ])
    # 葫芦
    card_arr = np.array([
        [1]+[0]*12 + 
        [1]*2+[0]*11 + 
        [1]*2+[0]*11 + 
        [0]+[0]*12
    ])
    card_arr = np.array(
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0.]
    )
    print(card_judge(card_arr))